package cn.lucky.core;

import cn.lucky.annotation.Lazy;
import cn.lucky.annotation.MyComponent;
import cn.lucky.annotation.Scope;
import cn.lucky.constant.ScopeType;
import cn.lucky.ex.NoSuchBeanDefinitionException;
import cn.lucky.vo.SimpleBeanDefinition;

import java.lang.reflect.Constructor;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SimpleIoC {
    //保存bean定义的map ，只要添加了注解的类，都会保存到这个map中
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    // 保存bean实例map
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    // 构造函数扫根包
    public SimpleIoC(String basePackage) throws Exception {
        ClassScanner scanner = new ClassScanner();
        // 获得根包下面的所有类对象
        List<Class<?>> classes = scanner.findClasses(basePackage);
        for (Class<?> clazz : classes) {
            if (clazz.isAnnotationPresent(MyComponent.class)) {
                processBeanDefinition(clazz);
            }
        }
    }

    // 保存bean定义信息和bean实例信息
    private void processBeanDefinition(Class<?> clazz) {
        // 获取类名，为了方便整个小写
        String beanName = clazz.getSimpleName().toLowerCase();
        // 获取类上面的注解
        Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
        boolean lazy = clazz.isAnnotationPresent(Lazy.class);
        ScopeType scope = (scopeAnnotation != null) ? scopeAnnotation.value() :ScopeType.SINGLETON;  // Default to singleton
        BeanDefinition beanDefinition = new SimpleBeanDefinition(clazz, scope,lazy);
        // 添加到bean定义map中  规则  单例和非懒加载的
        beanDefinitionMap.put(beanName, beanDefinition);
        if (ScopeType.SINGLETON.equals(scope) && !lazy) {
            singletonObjects.put(beanName, createBeanInstance(clazz));
        }
    }
    // 基于反射创建对象
    private Object createBeanInstance(Class<?> clazz) {
        try {
            Constructor<?> constructor = clazz.getDeclaredConstructor();
            return constructor.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Failed to create bean instance for class: " + clazz.getName(), e);
        }
    }

    // 获取bean对象
    public Object getBean(String beanName) {
        beanName = beanName.toLowerCase();
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition != null) {
            if (ScopeType.SINGLETON.equals(beanDefinition.getScope())) {
                Object o = singletonObjects.get(beanName);
                // bean定义有，且是单例，那就是lazy的,需要首次new了 保存到实例map中
                if(o==null && beanDefinition.isLazy()){
                    o=createBeanInstance(beanDefinition.getBeanClass());
                    singletonObjects.put(beanName,o);
                }
                return o ;
            } else if (ScopeType.PROTOTYPE.equals(beanDefinition.getScope())) {
                return createBeanInstance(beanDefinition.getBeanClass());
            }
        }
        if (beanDefinition == null) {
            throw new NoSuchBeanDefinitionException("BeanDefinition not found:" + beanName);
        }
        return null;
    }

    public <T>T getBean(String beanName,Class<T> clazz){
        return (T) getBean(beanName);
    }


}

